import pandas as pd
import matplotlib.pyplot as plt
import os
from datetime import datetime, timedelta

# ---------------------- 1. 全局配置 ----------------------


# 1.1 因子与复盘配置
BASIC_LIST = [
    'premium_rt',
    'fixed_premium',
    'curr_iss_amt',
    'bond_premium',
    'excess_increase',
    'bias_5',
    'deviation_degree',
    'option_value',
    'stock_wave',
    'theory_premium',
    'turnover_rt',
    'ytm_rt'
]


STD_FACTOR_LIST = [
    'std_premium_rt',
    'std_fixed_premium',
    'std_curr_iss_amt',
    'std_bond_premium',
    'std_excess_increase',
    'std_bias_5',
    'std_deviation_degree',
    'std_option_value',
    'std_stock_wave',
    'std_theory_premium',
    'std_turnover_rt',
    'std_ytm_rt'
]

NEUTRAL_FACTOR_LIST = [
    'neutral_premium_rt',
    'neutral_fixed_premium',
    'neutral_curr_iss_amt',
    'neutral_bond_premium',
    'neutral_excess_increase',
    'neutral_bias_5',
    'neutral_deviation_degree',
    'neutral_option_value',
    'neutral_stock_wave',
    'neutral_theory_premium',
    'neutral_turnover_rt',
    'neutral_ytm_rt'
]

FACTOR_LIST = BASIC_LIST + STD_FACTOR_LIST + NEUTRAL_FACTOR_LIST


#FACTOR_LIST = ['premium_rt']
FACTOR_SORT_RULE = {
    # 原始因子
    'premium_rt': True,
    'fixed_premium': True,
    'curr_iss_amt': True,
    'bond_premium': True,
    'excess_increase': True,
    'bias_5': True,
    'deviation_degree': True,
    'option_value': False,
    'stock_wave': False,
    'theory_premium': True,
    'turnover_rt': False,
    'ytm_rt': False,
    
    # 标准化因子（排序规则与原始因子一致）
    'std_premium_rt': True,
    'std_fixed_premium': True,
    'std_curr_iss_amt': True,
    'std_bond_premium': True,
    'std_excess_increase': True,
    'std_bias_5': True,
    'std_deviation_degree': True,
    'std_option_value': False,
    'std_stock_wave': False,
    'std_theory_premium': True,
    'std_turnover_rt': False,
    'std_ytm_rt': False,
    
    # 中性化因子（排序规则与原始因子一致）
    'neutral_premium_rt': True,
    'neutral_fixed_premium': True,
    'neutral_curr_iss_amt': True,
    'neutral_bond_premium': True,
    'neutral_excess_increase': True,
    'neutral_bias_5': True,
    'neutral_deviation_degree': True,
    'neutral_option_value': False,
    'neutral_stock_wave': False,
    'neutral_theory_premium': True,
    'neutral_turnover_rt': False,
    'neutral_ytm_rt': False
}

#FACTOR_SORT_RULE ={'premium_rt':True}

# ---------------------- 参数配置 ----------------------
SELECT_STOCK_NUM = 20  # 选前20名股票
DAYS_AGO = 1  # 复盘跨度（1=用昨天的因子，5=用5天前的因子）

# 1.2 存储路径
DATA_PATH = "数据存储路径"  # 与数据生成路径一致
DATA_PATH_FACTOR = "数据存储路径/因子裂变数据表"  # 与数据生成路径一致
CHART_SAVE_PATH = f"{DATA_PATH}/因子复盘图表/"
os.makedirs(CHART_SAVE_PATH, exist_ok=True)  # 自动创建图表文件夹

# 1.3 图表样式
plt.rcParams['font.sans-serif'] = ['SimHei', 'Arial Unicode MS']  # 中文显示
plt.rcParams['axes.unicode_minus'] = False  # 负号显示
CHART_SIZE = (12, 6)
CHART_DPI = 300
# ---------------------- 参数配置 ----------------------


# ---------------------- 2. 核心逻辑：读取单表数据+复盘 ----------------------
# 日期计算（今日市场数据 + DAYS_AGO天前的因子数据）
today = datetime.now().strftime("%Y%m%d")
factor_date = (datetime.now() - timedelta(days=DAYS_AGO)).strftime("%Y%m%d")

###########################################################################################
# 读取单表数据（从全量数据中提取所需字段）
# 今日全量数据：只需要「股票代码+当日涨跌幅」（用于计算收益）裂变因子全量数据
today_full_data = pd.read_excel(f"{DATA_PATH_FACTOR}/{today}_裂变因子全量数据.xlsx")
#适配代码
today_full_data['股票代码']=today_full_data['bond_id']
today_full_data['名称']=today_full_data['bond_nm']#redeem_real_days
today_full_data['强赎']=today_full_data['redeem_real_days']
today_full_data['当日涨跌幅(%)']=today_full_data['increase_rt']
today_market = today_full_data[["股票代码","名称","强赎","当日涨跌幅(%)","price","year_left"]].dropna()  # 清洗空值
###########################################################################################

#####分割线#####

###########################################################################################
# DAYS_AGO天前的全量数据：只需要「股票代码+10个因子」（用于筛选股票）
history_full_data = pd.read_excel(f"{DATA_PATH_FACTOR}/{factor_date}_裂变因子全量数据.xlsx")
#适配代码
history_full_data['股票代码']     =  history_full_data['bond_id']
history_full_data['名称']         =  history_full_data['bond_nm']
history_full_data['强赎']         =  history_full_data['redeem_real_days']
history_full_data['当日涨跌幅(%)'] =  history_full_data['increase_rt']
# 合并所有需要的列到一个列表中
history_factors = history_full_data[["股票代码","名称","强赎","price", "year_left"] + FACTOR_LIST].dropna()  # 清洗空值
#history_factors = history_full_data[["股票代码", "year_left"] + FACTOR_LIST].dropna()  # 此时FACTOR_LIST中的price会被包含，且只出现一次
###########################################################################################


# 初始化汇总结果
factor_summary = []

# 批量复盘10个因子
print(f"=== 【{today}】复盘{DAYS_AGO}天前因子表现 ===")
print(f"数据来源：今日全量数据（{today}）+ {DAYS_AGO}天前全量数据（{factor_date}）\n")

for factor_name in FACTOR_LIST:
    # 1. 提取当前因子的历史数据（股票代码+因子值）
    current_factor_data = history_factors[["股票代码", factor_name]]
    
    # 2. 关联历史因子值与今日涨跌幅（通过股票代码匹配）
    merged_data = pd.merge(
        current_factor_data,  # 左表：历史因子
        today_market,         # 右表：今日涨跌幅
        on="股票代码", 
        how="inner"           # 只保留两边都存在的股票
    ).dropna()  # 再次清洗空值（避免匹配后的数据缺失）
    
    # 3. 按因子规则筛选前20名股票
    sort_asc = FACTOR_SORT_RULE[factor_name]  # 排序方向（升序/降序），false或者true
    
    ############################################################################################
    # 筛选条件
    # 直接筛选行，重新赋值给merged_data
    print(merged_data.columns)
    print("\n\n")
    print(f"(----------------------{factor_name}----------------------)")

    # 在筛选条件前添加：动态获取price和year_left的列名
    # 优先用原始列名，若不存在则用合并后的后缀列名（x表示历史数据，y表示今日数据）
    # 动态获取price和year_left的列名（兼容普通因子和pricpipe因子）
    #因为我因子里面也有price，所以price有两个，需要动态处理列名
    price_col = "price" if "price" in merged_data.columns else "price_x"  # 历史price用price_x
    year_left_col = "year_left" if "year_left" in merged_data.columns else "year_left_x"  # 历史year_left用year_left_x

    # 筛选条件
    merged_data = merged_data[merged_data[price_col] > 100]
    merged_data = merged_data[merged_data[price_col] < 160]
    merged_data = merged_data[merged_data[year_left_col] > 1]
    merged_data = merged_data[merged_data["强赎"] < 10]

    ############################################################################################
    factor_top20 = merged_data.sort_values(by=factor_name, ascending=sort_asc).head(SELECT_STOCK_NUM)

    print(factor_top20.head(30))
    # 4. 计算复盘指标
    avg_return = factor_top20["当日涨跌幅(%)"].mean()  # 平均涨跌幅
    up_count = len(factor_top20[factor_top20["当日涨跌幅(%)"] > 0])  # 上涨股票数
    up_rate = (up_count / SELECT_STOCK_NUM) * 100  # 上涨概率
    
    # 5. 打印结果+存入汇总表
    print(f"【{factor_name}】平均涨跌幅：{avg_return:.2f}% | 上涨概率：{up_rate:.1f}%")
    factor_summary.append({
        "复盘日期": today,
        "因子名称": factor_name,
        "因子数据日期": factor_date,
        "平均涨跌幅(%)": round(avg_return, 2),
        "上涨概率(%)": round(up_rate, 1)
    })


# ---------------------- 3. 保存汇总表 ----------------------
summary_df = pd.DataFrame(factor_summary)
summary_path = f"{DATA_PATH}/{today}_复盘{DAYS_AGO}天前因子汇总.csv"
summary_df.to_csv(summary_path, index=False, encoding="utf-8-sig")
print(f"\n=== 汇总表已保存至：{summary_path} ===")


# ---------------------- 4. 生成自适应柱状图 ----------------------
def create_factor_bar_chart(summary_data, save_path, today_date, days_ago):
    # 按平均涨跌幅降序排列，更直观
    plot_data = summary_data.sort_values(by="平均涨跌幅(%)", ascending=False)
    factors = plot_data["因子名称"]
    avg_returns = plot_data["平均涨跌幅(%)"]
    
    # 创建画布
    fig, ax = plt.subplots(figsize=CHART_SIZE, dpi=CHART_DPI)
    
    # 柱子颜色（涨=红，跌=绿）
    colors = ["#E53935" if x > 0 else "#43A047" for x in avg_returns]
    
    # 绘制柱状图
    bars = ax.bar(
        x=range(len(factors)),
        height=avg_returns,
        color=colors,
        width=0.6,
        edgecolor="#212121",
        linewidth=0.5
    )
    
    # 优化x轴标签（避免重叠）
    ax.set_xticks(range(len(factors)))
    ax.set_xticklabels(factors, rotation=45, ha="right", fontsize=10)
    
    # 添加数值标签（顶部/底部显示具体值）
    for bar, value in zip(bars, avg_returns):
        ax.text(
            bar.get_x() + bar.get_width()/2,
            bar.get_height() + (0.05 if value > 0 else -0.15),
            f"{value:.2f}%",
            ha="center", va="bottom" if value > 0 else "top",
            fontsize=9, fontweight="bold"
        )
    
    # 标题与坐标轴
    ax.set_title(
        f"【{today_date}】复盘{days_ago}天前因子前{SELECT_STOCK_NUM}名平均涨跌幅",
        fontsize=14, fontweight="bold", pad=20
    )
    ax.set_xlabel("因子名称", fontsize=11, labelpad=10)
    ax.set_ylabel("平均涨跌幅(%)", fontsize=11, labelpad=10)
    ax.yaxis.grid(True, alpha=0.3, linestyle="--")  # 横向网格线
    
    # 自适应布局+保存
    plt.tight_layout()
    chart_filename = f"{save_path}/{today_date}_复盘{days_ago}天前因子对比图.png"
    plt.savefig(chart_filename, dpi=CHART_DPI, bbox_inches="tight")
    plt.close()
    return chart_filename


# 执行绘图
chart_path = create_factor_bar_chart(summary_df, CHART_SAVE_PATH, today, DAYS_AGO)
print(f"=== 柱状图已保存至：{chart_path} ===")